﻿using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;

namespace SignalTable
{
    partial class Parabola
    {
        public int numInputs, numOfWeights, numOutputs, numLayers, numEpochs, errMeasure, numVectors, numTestVect, lastColumnContainsOutliers = 0;
        public double minDw = 0.001, maxDw = 10, error = 0, accuracy = 0, meanOutlier = 0, offset = 0.997, delta = 0.5, errExp = 2, oldWeightTest, oldError = -1;
        public double[] dw0 = { 0.0, 0.3, 0.3, 0.5, 0.5, 0.5, 0.5, 0.5 };
        public int[] Layer, numHidden;
        double[, ,] SignalTableY, SignalTableSumWX, weights, deltaa, Zamrazanie;
        public double[,] TrainingDataSet, SuperWagi;
        public bool classification, RandomWeights = false;
        double licznik = 0, licznik2;
        bool[, ,] ZamrazanieBool;

        public Parabola(double[,] DataSet, int[] numHidden, int numEpochs = 20, bool classification = true,
                   bool RandomWeights = false, int errMeasure = 0, double delta = 0.5, double errExp = 2)
        {
            this.numEpochs = numEpochs;
            this.RandomWeights = RandomWeights;
            this.numHidden = numHidden;
            if (numHidden[0] == 0) //How many layers are in network
                numLayers = 2;
            else numLayers = 2 + numHidden.Length;

            this.classification = classification;
            this.errMeasure = errMeasure;
            this.delta = delta;
            this.errExp = errExp;
            numInputs = DataSet.GetLength(1) - 1; //last=class/Y, 
            //numVectors = DataSet.GetLength(0);          

            TrainingDataSet = DataSet;
            numVectors = DataSet.GetLength(0);

            if (classification)//How many outputs
            {
                SortedSet<int> Nout = new SortedSet<int>();
                for (int v = 0; v < TrainingDataSet.GetLength(0); v++)
                    Nout.Add((int)TrainingDataSet[v, numInputs]);
                numOutputs = Nout.Count;
            }
            else //regression
                numOutputs = 1;

            this.numEpochs = numEpochs;
            CreateNetwork();
        }

        private void CreateNetwork()
        {
            Layer = new int[numLayers];//Layer table gives us information about how many neurons are in each layer
            Layer[0] = numInputs;
            for (int i = 1; i < numLayers - 1; i++)
                Layer[i] = numHidden[i - 1];
            Layer[numLayers - 1] = numOutputs;
            int maxNeurons = numInputs;
            for (int i = 0; i < numLayers; i++)
                if (maxNeurons < Layer[i])
                    maxNeurons = Layer[i];

            licznik2 = 1 + Layer[2] * (Layer[1] + 1) * 0.2 + Layer[2] * 0.8;
            weights = new double[numLayers, maxNeurons, maxNeurons + 1];
            deltaa = new double[weights.GetLength(0), weights.GetLength(1), weights.GetLength(2)];
            SignalTableY = new double[TrainingDataSet.GetLength(0), numLayers, maxNeurons];
            SignalTableSumWX = new double[TrainingDataSet.GetLength(0), numLayers, maxNeurons];
            Zamrazanie = new double[numLayers, maxNeurons, maxNeurons + 1];
            ZamrazanieBool = new bool[numLayers, maxNeurons, maxNeurons + 1];
            
            numOfWeights = (Layer[1] + 1) * Layer[2] + (Layer[0] + 1) * Layer[1];
            string[] WeightsFromFile = { "" };
            if (!RandomWeights)
                WeightsFromFile = File.ReadAllLines(@"../../../datasets/weights.txt");
            int wff = 0;

            Random rnd = new Random();
            for (int L = 1; L < numLayers; L++)
            {
                for (int n = 0; n < Layer[L]; n++)
                {
                    if (RandomWeights)
                    {
                        for (int w = 0; w < Layer[L - 1] + 1; w++)
                        {
                            weights[L, n, w] = 0.5 - rnd.NextDouble(); //adding random weights
                            deltaa[L, n, w] = dw0[L]; //delta
                        }
                    }
                    else
                    {
                        for (int w = 0; w < Layer[L - 1] + 1; w++)
                        {
                            weights[L, n, w] = 0.5 - Double.Parse(WeightsFromFile[wff++], System.Globalization.CultureInfo.InvariantCulture); //adding weights from file
                            deltaa[L, n, w] = dw0[L]; //delta
                        }
                    }
                }
            }
        }

        public void VSS(double d1, double d2, int datasetNumber, int x, int MaxLicznikErr, bool sprWagi, bool zamrazaniee, int n1, int n2, int num)
        {
            FillSignalTable(TrainingDataSet, TrainingDataSet.GetLength(0));
            oldError = getError(TrainingDataSet, 1);
            string sss = @"../../../results/wynik_";
            //StreamWriter para = new StreamWriter(@"../../../results/Parabola_" + datasetNumber.ToString() + "_" + x.ToString() + ".txt");
            StreamWriter sw = new StreamWriter(sss + datasetNumber.ToString() + "_" + x.ToString() + ".txt", true);
            sw.Write(datasetNumber + "\t" + d1 + "\t" + d2 + "\t" + 0 + "\t" + oldError / numVectors + "\t");
            int indeksPara = 0;
            //para.WriteLine("indeks \t a>0 \t epoch \t L \t n \t w \t x1 \t x2 \t x3 \t y1 \t y2 \t y3 \t p \t q \t y4");
            double Error = oldError, dw, dw1, dw2, x1, x2, x3, y1, y2, y3, a, b, c, p, RevertWeight,
            SupOldError, tmperror, tmpL, tmpW, tmpN, newL, newW, newE, newN;
            int ile = 0;
            for (int e = 0; e < numEpochs; e++)
            {
                int licznikSpadku = 0;
                SuperWagi = new double[numOfWeights, 4];
                for (int L = 1; L < numLayers; L++)
                {
                    for (int n = 0; n < Layer[L]; n++)
                    {
                        for (int w = 0; w < Layer[L - 1] + 1; w++)
                        {
                            SupOldError = oldError;
                            if (ZamrazanieBool[L, n, w])
                            {
                                if (Zamrazanie[L, n, w] > 0)
                                {
                                    Zamrazanie[L, n, w] -= (double)n1 / n2;
                                    continue;
                                }
                                ZamrazanieBool[L, n, w] = false;
                            }
                            bool errorDecreased = false;
                            dw = deltaa[L, n, w]; //deltaa contains the value the weight changed about in the previous epoch
                            if (dw > maxDw)
                                dw = maxDw;
                            else if (dw < -maxDw)
                                dw = -maxDw;

                            double oldW = weights[L, n, w]; //1
                            x1 = weights[L, n, w];
                            y1 = Error;
                            oldWeightTest = weights[L, n, w];
                            dw1 = d1 * dw;
                            RevertWeight = weights[L, n, w];
                            weights[L, n, w] += dw1; //2
                            x2 = weights[L, n, w];
                            rec(L, n, w);
                            if ((y2 = Error = getError(TrainingDataSet, L)) < oldError)
                            {
                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                if (ile >= num)
                                {
                                    sw.WriteLine();
                                    sw.Close();
                                    return;
                                }
                                oldError = Error;
                                errorDecreased = true;
                                deltaa[L, n, w] = dw1;
                                oldWeightTest = weights[L, n, w];
                                dw2 = d2 * dw;
                                weights[L, n, w] += dw2; //3
                                x3 = weights[L, n, w];
                                rec(L, n, w);
                                if ((y3 = Error = getError(TrainingDataSet, L)) < oldError)
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldError = Error;
                                    deltaa[L, n, w] += dw2;
                                    oldWeightTest = weights[L, n, w];
                                    double d = (x1 - x2) * (x1 - x3) * (x2 - x3);
                                    a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / d;
                                    //if (a < 0)
                                    //{
                                    //    indeksPara++;
                                    //    //para.WriteLine(indeksPara + "\t false \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t");
                                    //}
                                    //else
                                    //{
                                    //    indeksPara++;
                                    //    //para.Write(indeksPara + "\t true \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t" + x1 + "\t" + x2 + "\t" + x3 + "\t" + y1 + "\t" + y2 + "\t" + y3 + "\t");
                                    //}
                                    if (a > 0)
                                    {
                                        b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3)) / d;
                                        c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / d;
                                        p = -b / (2 * a);
                                        if (p > maxDw)
                                            p = maxDw;
                                        else if (p < maxDw)
                                            p = -maxDw;

                                        double q = c - b * b / (4 * a);
                                        double hehehe = weights[L, n, w];
                                        weights[L, n, w] = p;
                                        rec(L, n, w);
                                        if ((Error = getError(TrainingDataSet, L)) < oldError)
                                        {
                                            //para.WriteLine(p + "\t" + q + "\t" + Error);
                                            ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                            if (ile >= num)
                                            {
                                                sw.WriteLine();
                                                sw.Close();
                                                return;
                                            }
                                            oldError = Error;
                                            deltaa[L, n, w] += p - hehehe;
                                        }
                                        else
                                        {
                                            ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                            //para.WriteLine(p + "\t" + q + "\t" + Error);
                                            if (ile >= num)
                                            {
                                                sw.WriteLine();
                                                sw.Close();
                                                return;
                                            }
                                            oldWeightTest = weights[L, n, w];
                                            weights[L, n, w] = hehehe;
                                            rec(L, n, w);
                                        }
                                    }

                                }
                                else
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldWeightTest = weights[L, n, w];
                                    weights[L, n, w] -= dw2;
                                    rec(L, n, w);
                                }

                            }
                            else
                            {
                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                if (ile >= num)
                                {
                                    sw.WriteLine();
                                    sw.Close();
                                    return;
                                }
                                oldWeightTest = weights[L, n, w];
                                weights[L, n, w] = RevertWeight;
                                dw1 = d1 * dw;
                                weights[L, n, w] -= dw1;
                                x2 = weights[L, n, w];
                                rec(L, n, w);
                                if ((y2 = Error = getError(TrainingDataSet, L)) < oldError)
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldError = Error;
                                    deltaa[L, n, w] = -dw1;
                                    errorDecreased = true;
                                    oldWeightTest = weights[L, n, w];
                                    dw2 = d2 * dw;
                                    weights[L, n, w] -= dw2;
                                    x3 = weights[L, n, w];
                                    rec(L, n, w);
                                    if ((y3 = Error = getError(TrainingDataSet, L)) < oldError)
                                    {
                                        ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                        if (ile >= num)
                                        {
                                            sw.WriteLine();
                                            sw.Close();
                                            return;
                                        }
                                        oldError = Error;
                                        deltaa[L, n, w] -= dw2;
                                        oldWeightTest = weights[L, n, w];
                                        double d = (x1 - x2) * (x1 - x3) * (x2 - x3);
                                        a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / d;
                                        //if (a < 0)
                                        //{
                                        //    indeksPara++;
                                        //    // para.WriteLine(indeksPara + "\t false \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t");
                                        //}
                                        //else
                                        //{
                                        //    indeksPara++;
                                        //    // para.Write(indeksPara + "\t true \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t" + x1 + "\t" + x2 + "\t" + x3 + "\t" + y1 + "\t" + y2 + "\t" + y3 + "\t");
                                        //}
                                        if (a > 0)
                                        {
                                            b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3)) / d;
                                            c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / d;
                                            p = -b / (2 * a);
                                            double q = c - b * b / (4 * a);
                                            double hehehe = weights[L, n, w];
                                            weights[L, n, w] = p;
                                            rec(L, n, w);
                                            if ((Error = getError(TrainingDataSet, L)) < oldError)
                                            {
                                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                                //    para.WriteLine(p + "\t" + q + "\t" + Error);
                                                if (ile >= num)
                                                {
                                                    sw.WriteLine();
                                                    sw.Close();
                                                    return;
                                                }
                                                oldError = Error;
                                                deltaa[L, n, w] += p - hehehe;
                                            }
                                            else
                                            {
                                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                                //   para.WriteLine(p + "\t" + q + "\t" + Error);
                                                if (ile >=  num)
                                                {
                                                    sw.WriteLine();
                                                    sw.Close();
                                                    return;
                                                }
                                                oldWeightTest = weights[L, n, w];
                                                weights[L, n, w] = hehehe;
                                                rec(L, n, w);
                                            }
                                        }

                                    }
                                    else
                                    {
                                        ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                        if (ile >= num)
                                        {
                                            sw.WriteLine();
                                            sw.Close();
                                            return;
                                        }
                                        oldWeightTest = weights[L, n, w];
                                        weights[L, n, w] += dw2;
                                        rec(L, n, w);
                                    }
                                }
                                if (!errorDecreased)
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    if (zamrazaniee == true)
                                        if (++Zamrazanie[L, n, w] >= n1)
                                            ZamrazanieBool[L, n, w] = true;
                                    oldWeightTest = weights[L, n, w];
                                    weights[L, n, w] = oldW;
                                    rec(L, n, w);
                                    deltaa[L, n, w] = 0.5 * dw;
                                    if (deltaa[L, n, w] < minDw && deltaa[L, n, w] >= 0)
                                        deltaa[L, n, w] = minDw;
                                    else if (deltaa[L, n, w] > -minDw)
                                        deltaa[L, n, w] = -minDw;
                                }
                            }

                            bool hehe = false;
                            for (int i = 0; i < numOfWeights; i++)
                            {
                                if (hehe == true)
                                    break;
                                if (SuperWagi[i, 0] < SupOldError - Error)
                                {
                                    licznikSpadku++;
                                    hehe = true;
                                    tmperror = SuperWagi[i, 0]; tmpL = SuperWagi[i, 1]; tmpW = SuperWagi[i, 3]; tmpN = SuperWagi[i, 2];
                                    SuperWagi[i, 0] = SupOldError - Error; SuperWagi[i, 1] = L; SuperWagi[i, 2] = n; SuperWagi[i, 3] = w;
                                    for (int j = i + 1; j < numOfWeights; j++)
                                    {
                                        newE = SuperWagi[j, 0]; newW = SuperWagi[j, 3]; newL = SuperWagi[j, 1]; newN = SuperWagi[j, 2];
                                        SuperWagi[j, 0] = tmperror; SuperWagi[j, 3] = tmpW;  SuperWagi[j, 2] = tmpN; SuperWagi[j, 1] = tmpL;
                                        tmperror = newE; tmpL = newL; tmpN = newN; tmpW = newW;
                                    }
                                }
                            }
                        }//for w
                    }//for n
                }//for L
                if (sprWagi == true)
                {
                    for (int ww = 0; ww < 0.2 * licznikSpadku; ww++)
                    {
                        if (SuperWagi[ww, 0] != 0)
                        {
                            int L = (int)SuperWagi[ww, 1], n = (int)SuperWagi[ww, 2], w = (int)SuperWagi[ww, 3];
                            bool errorDecreased = false;
                            dw = deltaa[L, n, w]; //deltaa contains the value the weight changed about in the previous epoch
                            double oldW = weights[L, n, w]; //1
                            x1 = weights[L, n, w];
                            y1 = Error;
                            oldWeightTest = weights[L, n, w];
                            dw1 = d1 * dw;
                            RevertWeight = weights[L, n, w];
                            weights[L, n, w] += dw1; //2
                            x2 = weights[L, n, w];
                            rec(L, n, w);
                            if ((y2 = Error = getError(TrainingDataSet, L)) < oldError)
                            {
                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                if (ile >=  num)
                                {
                                    sw.WriteLine();
                                    sw.Close();
                                    return;
                                }
                                oldError = Error;
                                errorDecreased = true;
                                deltaa[L, n, w] = dw1;
                                oldWeightTest = weights[L, n, w];
                                dw2 = d2 * dw;
                                weights[L, n, w] += dw2; //3
                                x3 = weights[L, n, w];
                                rec(L, n, w);
                                if ((y3 = Error = getError(TrainingDataSet, L)) < oldError)
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldError = Error;
                                    deltaa[L, n, w] += dw2;
                                    oldWeightTest = weights[L, n, w];
                                    double d = (x1 - x2) * (x1 - x3) * (x2 - x3);
                                    a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / d;
                                    //if (a < 0)
                                    //{
                                    //    indeksPara++;
                                    //    // para.WriteLine(indeksPara + "\t false \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t");
                                    //}
                                    //else
                                    //{
                                    //    indeksPara++;
                                    //    //  para.Write(indeksPara + "\t true \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t" + x1 + "\t" + x2 + "\t" + x3 + "\t" + y1 + "\t" + y2 + "\t" + y3 + "\t");
                                    //}
                                    if (a > 0)
                                    {
                                        b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3)) / d;
                                        c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / d;
                                        p = -b / (2 * a);
                                        double q = c - b * b / (4 * a);
                                        double hehehe = weights[L, n, w];
                                        weights[L, n, w] = p;
                                        rec(L, n, w);
                                        if ((Error = getError(TrainingDataSet, L)) < oldError)
                                        {
                                            //    para.WriteLine(p + "\t" + q + "\t" + Error);
                                            ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                            if (ile >= num)
                                            {
                                                sw.WriteLine();
                                                sw.Close();
                                                return;
                                            }
                                            oldError = Error;
                                            deltaa[L, n, w] += p - hehehe;
                                        }
                                        else
                                        {
                                            //  para.WriteLine(p + "\t" + q + "\t" + Error);
                                            ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                            if (ile >= num)
                                            {
                                                sw.WriteLine();
                                                sw.Close();
                                                return;
                                            }
                                            oldWeightTest = weights[L, n, w];
                                            weights[L, n, w] = hehehe;
                                            rec(L, n, w);
                                        }
                                    }

                                }
                                else
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldWeightTest = weights[L, n, w];
                                    weights[L, n, w] -= dw2;
                                    rec(L, n, w);
                                }

                            }
                            else
                            {
                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                if (ile >= num)
                                {
                                    sw.WriteLine();
                                    sw.Close();
                                    return;
                                }
                                oldWeightTest = weights[L, n, w];
                                weights[L, n, w] = RevertWeight;
                                dw1 = d1 * dw;
                                weights[L, n, w] -= dw1;
                                x2 = weights[L, n, w];
                                rec(L, n, w);
                                if ((y2 = Error = getError(TrainingDataSet, L)) < oldError)
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldError = Error;
                                    deltaa[L, n, w] = -dw1;
                                    errorDecreased = true;
                                    oldWeightTest = weights[L, n, w];
                                    dw2 = d2 * dw;
                                    weights[L, n, w] -= dw2;
                                    x3 = weights[L, n, w];
                                    rec(L, n, w);
                                    if ((y3 = Error = getError(TrainingDataSet, L)) < oldError)
                                    {
                                        ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                        if (ile >= num)
                                        {
                                            sw.WriteLine();
                                            sw.Close();
                                            return;
                                        }
                                        oldError = Error;
                                        deltaa[L, n, w] -= dw2;
                                        oldWeightTest = weights[L, n, w];
                                        double d = (x1 - x2) * (x1 - x3) * (x2 - x3);
                                        a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / d;
                                        //if (a < 0)
                                        //{
                                        //    indeksPara++;
                                        //    //para.WriteLine(indeksPara + "\t false \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t");
                                        //}
                                        //else
                                        //{
                                        //    indeksPara++;
                                        //    //para.Write(indeksPara + "\t true \t" + e + "\t" + L + "\t" + n + "\t" + w + "\t" + x1 + "\t" + x2 + "\t" + x3 + "\t" + y1 + "\t" + y2 + "\t" + y3 + "\t");
                                        //}
                                        if (a > 0)
                                        {
                                            b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3)) / d;
                                            c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / d;
                                            p = -b / (2 * a);
                                            double q = c - b * b / (4 * a);
                                            double hehehe = weights[L, n, w];
                                            weights[L, n, w] = p;
                                            rec(L, n, w);
                                            if ((Error = getError(TrainingDataSet, L)) < oldError)
                                            {
                                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                                if (ile >= num)
                                                {
                                                    sw.WriteLine();
                                                    sw.Close();
                                                    return;
                                                }
                                                oldError = Error;
                                                deltaa[L, n, w] += p - hehehe;
                                            }
                                            else
                                            {
                                                //   para.WriteLine(p + "\t" + q + "\t" + Error);
                                                ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                                if (ile >= num)
                                                {
                                                    sw.WriteLine();
                                                    sw.Close();
                                                    return;
                                                }
                                                oldWeightTest = weights[L, n, w];
                                                weights[L, n, w] = hehehe;
                                                rec(L, n, w);
                                            }
                                        }

                                    }
                                    else
                                    {
                                        ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                        if (ile >= num)
                                        {
                                            sw.WriteLine();
                                            sw.Close();
                                            return;
                                        }
                                        oldWeightTest = weights[L, n, w];
                                        weights[L, n, w] += dw2;
                                        rec(L, n, w);
                                    }
                                }
                                if (!errorDecreased)
                                {
                                    ile = SaveError(MaxLicznikErr, num, sw, Error, ile);
                                    if (ile >= num)
                                    {
                                        sw.WriteLine();
                                        sw.Close();
                                        return;
                                    }
                                    oldWeightTest = weights[L, n, w];
                                    weights[L, n, w] = oldW;
                                    rec(L, n, w);
                                    deltaa[L, n, w] = 0.5 * dw;
                                    if (deltaa[L, n, w] < minDw && deltaa[L, n, w] >= 0)
                                        deltaa[L, n, w] = minDw;
                                    else if (deltaa[L, n, w] > -minDw)
                                        deltaa[L, n, w] = -minDw;
                                }
                            }
                        }
                    }
                }
            } //for e
            //sw = new StreamWriter(sss + datasetNumber.ToString() + "_" + x.ToString() + ".txt", true);
            sw.WriteLine();
            sw.Close();
            //para.Close();
        }
        private int SaveError(int MaxLicznikErr, int num, StreamWriter sw, double Error, int ile)
        {
	        if (licznik >= MaxLicznikErr && ile < num)
	        {
	            sw.Write(Error / numVectors + "\t");
	            ile++; licznik = 0;
	        }
	        return ile;
        }

        private void FillSignalTable(double[,] DataSet1, int numVect)
        {
            for (int vect = 0; vect < numVect; vect++)
            {
                for (int n = 0; n < Layer[0]; n++)
                    SignalTableY[vect, 0, n] = DataSet1[vect, n];

                for (int L = 1; L < numLayers; L++)
                {
                    for (int n = 0; n < Layer[L]; n++)
                    {
                        SignalTableSumWX[vect, L, n] = 0;
                        for (int w = 0; w < Layer[L - 1]; w++)
                        {
                            SignalTableSumWX[vect, L, n] += weights[L, n, w] * SignalTableY[vect, L - 1, w];
                        }
                        SignalTableSumWX[vect, L, n] += weights[L, n, Layer[L - 1]]; //bias 
                        SignalTableY[vect, L, n] = Math.Tanh(SignalTableSumWX[vect, L, n]);//y
                    }
                }
            }
        }

        public void rec(int L1, int n1, int w1) //recalculating Y and SumWX for each vector after weight change [only the neuron which weight was changed, and all in the upper layers]
        {
            for (int vect = 0; vect < TrainingDataSet.GetLength(0); vect++)
            {
                if (w1 == Layer[L1 - 1])
                {
                    SignalTableSumWX[vect, L1, n1] += weights[L1, n1, w1];
                    SignalTableSumWX[vect, L1, n1] -= oldWeightTest;
                }
                else
                {
                    SignalTableSumWX[vect, L1, n1] += weights[L1, n1, w1] * SignalTableY[vect, L1 - 1, w1];
                    SignalTableSumWX[vect, L1, n1] -= oldWeightTest * SignalTableY[vect, L1 - 1, w1];
                }
                double oldY = SignalTableY[vect, L1, n1];
                SignalTableY[vect, L1, n1] = Math.Tanh(SignalTableSumWX[vect, L1, n1]);
                if (L1 != numLayers - 1)
                {
                    for (int L = L1 + 1; L < L1 + 2; L++)
                    {
                        for (int n = 0; n < Layer[L]; n++)
                        {
                            SignalTableSumWX[vect, L, n] += weights[L, n, n1] * SignalTableY[vect, L - 1, n1];
                            SignalTableSumWX[vect, L, n] -= weights[L, n, n1] * oldY;
                            SignalTableY[vect, L, n] = Math.Tanh(SignalTableSumWX[vect, L, n]); //y
                        }
                    }
                    for (int L = L1 + 2; L < numLayers; L++)
                    {
                        for (int n = 0; n < Layer[L]; n++)
                        {
                            SignalTableSumWX[vect, L, n] = 0;
                            for (int w = 0; w < Layer[L - 1]; w++)
                            {
                                SignalTableSumWX[vect, L, n] += weights[L, n, w] * SignalTableY[vect, L - 1, w];
                            }
                            SignalTableSumWX[vect, L, n] += weights[L, n, Layer[L - 1]]; //bias 
                            SignalTableY[vect, L, n] = Math.Tanh(SignalTableSumWX[vect, L, n]);//y
                        }
                    }
                }
            }
        }

        public double getError(double[,] DataSet1, int L1, double errorExponent = 2, int test = 0, bool outliers = false, int errMeasure = 0, double delta = 0.5)
        //calculating network (all signals are stored in SignalTable)
        {
            if (L1 == 1)
                licznik += licznik2;
            else
                licznik++;

            double Error = 0;
            int numVect = DataSet1.GetLength(0);
            numTestVect = numVect;
            accuracy = 0;

            if (classification)
            {
                int L = numLayers - 1;
                double maxY, maxN;
                for (int vect = 0; vect < numVect; vect++)
                {
                    maxY = -1; maxN = -1;

                    for (int n = 0; n < Layer[L]; n++)
                    {
                        if (SignalTableY[vect, L, n] > maxY)
                        {
                            maxY = SignalTableY[vect, L, n];
                            maxN = n;
                        }
                        int y = (int)DataSet1[vect, Layer[0]] - 1;
                        //class numbering starts from 1
                        if (n == y)  //N[L][y].Y is expected to be 1;
                        {
                            if (SignalTableY[vect, L, n] < offset)
                                Error += Math.Pow(Math.Abs(SignalTableY[vect, L, n] - 1), errorExponent); //calculating network for classification
                        }
                        else  //N[L][y].Y is expected to be -1;
                        {
                            if (SignalTableY[vect, L, n] > -offset)
                                Error += Math.Pow(Math.Abs(SignalTableY[vect, L, n] + 1), errorExponent); //calculating network for classification
                        }
                    }
                    if (maxN == DataSet1[vect, Layer[0]] - 1)
                        accuracy++;
                }
            }
            else
            {
                int L = numLayers - 1;
                for (int vect = 0; vect < numVect; vect++)
                {
                    for (int n = 0; n < Layer[L]; n++)
                    {
                        SignalTableY[vect, L, n] = SignalTableSumWX[vect, L, n];
                        Error += Math.Pow(Math.Abs(SignalTableY[vect, L, n] - DataSet1[vect, Layer[0]]), errorExponent); //calculating network for regression
                    }

                }
            }
            return Error;
        }
    }
}